/**
 * Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.x2.core.auth;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.x2.base.auth.context.LoginContextHolder;
import com.x2.base.auth.jwt.JwtTokenUtil;
import com.x2.base.auth.jwt.payload.JwtPayLoad;
import com.x2.base.auth.model.AuthVo;
import com.x2.base.auth.model.LoginUser;
import com.x2.base.auth.service.AuthService;
import com.x2.base.consts.ConstantsContext;
import com.x2.core.auth.cache.SessionManager;
import com.x2.core.auth.util.SaltUtil;
import com.x2.core.constant.factory.ConstantFactory;
import com.x2.core.constant.factory.UserFactory;
import com.x2.core.constant.state.ManagerStatus;
import com.x2.core.exception.AuthException;
import com.x2.core.exception.AuthExceptionEnum;
import com.x2.core.listener.ConfigListener;
import com.x2.core.util.HttpContext;
import com.x2.core.util.SpringContextHolder;
import com.x2.modular.system.entity.User;
import com.x2.modular.system.service.*;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@DependsOn("springContextHolder")
@Transactional(readOnly = true)
public class AuthServiceImpl implements AuthService {

    @Autowired
    private UserService userService;
    @Autowired
    private MenuService menuService;
    @Autowired
    private DictService dictService;
    @Autowired
    private SessionManager sessionManager;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private DeptService deptService;

    public static AuthService me() {
        return SpringContextHolder.getBean(AuthService.class);
    }


    @Override
    public String login(String username) {
        return login(username, null);
    }

    @Override
    public String login(String username, String password) {
        User user = userService.getByAccount(username);
        // 账号不存在
        if (null == user) {
            throw new AuthException(AuthExceptionEnum.USERNAME_PWD_ERROR);
        }
        //验证账号密码是否正确
        if (password != null) {
            String requestMd5 = SaltUtil.md5Encrypt(password, user.getSalt());
            String dbMd5 = user.getPassword();
            if (dbMd5 == null || !dbMd5.equalsIgnoreCase(requestMd5)) {
                throw new AuthException(AuthExceptionEnum.USERNAME_PWD_ERROR);
            }
        }
        return login(user);
    }

    private String login(User user){
            // 账号被冻结
            if (!user.getStatus().equals(ManagerStatus.OK.getCode())) {
                throw new AuthException(AuthExceptionEnum.ACCOUNT_FREEZE_ERROR);
            }

            JwtPayLoad payLoad = new JwtPayLoad(user.getUserId(), user.getName(), String.valueOf(user.getDeptId()));
            //创建token
            String token = JwtTokenUtil.generateToken(payLoad);
            //创建登录会话
            sessionManager.createSession(token, user(user.getAccount()));
            //创建cookie
            addLoginCookie(token);
            return token;
    }
    @Override
    public void addLoginCookie(String token) {
        //创建cookie
        Cookie authorization = new Cookie(ConstantsContext.getTokenHeaderName(), token);
        authorization.setMaxAge(ConstantsContext.getJwtSecretExpireSec().intValue());
        authorization.setHttpOnly(true);
        authorization.setPath("/");
        HttpServletResponse response = HttpContext.getResponse();
        response.addCookie(authorization);
    }

    @Override
    public void logout() {
        String token = LoginContextHolder.getContext().getToken();
        //删除Auth相关cookies
        Cookie[] cookies = HttpContext.getRequest().getCookies();
        for (Cookie cookie : cookies) {
            String tokenHeader = ConstantsContext.getTokenHeaderName();
            if (tokenHeader.equalsIgnoreCase(cookie.getName())) {
                Cookie temp = new Cookie(cookie.getName(), "");
                temp.setMaxAge(0);
                temp.setPath("/");
                HttpContext.getResponse().addCookie(temp);
            }
        }
        //删除会话
        sessionManager.removeSession(token);
    }

    @Override
    public LoginUser user(String account) {
        User user = userService.getByAccount(account);
        LoginUser loginUser = UserFactory.createLoginUser(user);
        return loginUser;
    }

    @Override
    public List<String> findPermissionsByRoleId(Long roleId) {
        return menuService.getResUrlsByRoleId(roleId);
    }

    @Override
    public boolean check(String[] roleNames) {
        LoginUser user = LoginContextHolder.getContext().getUser();
        if (null == user) {
            return false;
        }
        ArrayList<String> objects = CollectionUtil.newArrayList(roleNames);
        String join = CollectionUtil.join(objects, ",");
        if (LoginContextHolder.getContext().hasAnyRoles(join)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean checkAll() {
        HttpServletRequest request = HttpContext.getRequest();
        LoginUser user = LoginContextHolder.getContext().getUser();
        if (null == user) {
            return false;
        }
        String requestUri = request.getRequestURI().replaceFirst(ConfigListener.getConf().get("contextPath"), "");
        String[] str = requestUri.split("/");
        if (str.length > 3) {
            requestUri = "/" + str[1] + "/" + str[2];
        }
        return LoginContextHolder.getContext().hasPermission(requestUri);
    }
}
